int read_file(int file, char* buf, int nBytes)
{
	int bytesRead = 0, fileBytesLeft = 0;
	ulong numSingleIndirect = 0, numDoubleIndirect = 0, numTripleIndirect = 0;
	char* bufPnt = buf;
	OFT* fileEntry = runningProc->files[file];
	EXT2_DISK* diskInfo;
	
	if (fileEntry == 0)
	{
		printf("File doesn't exist!\n");
		return -1;
	}
	
	if ((fileEntry->mode == FILE_READ) || (fileEntry->mode == FILE_READ_WRITE))
	{
		if (get_device_info(fileEntry->memInode->location.deviceHandle, &diskInfo) == -1)
			return -1;
			
		/* Make sure under 8KB */
		if (nBytes > MAX_BLOCK_SIZE)
			nBytes = MAX_BLOCK_SIZE;
		
		/* Make sure nBytes <= i_size */
		if (nBytes > fileEntry->memInode->inode.i_size)
			nBytes = fileEntry->memInode->inode.i_size;
			
		numSingleIndirect = diskInfo->blockSize / sizeof(ulong);
		numDoubleIndirect = numSingleIndirect * numSingleIndirect;
		numTripleIndirect = numDoubleIndirect * numSingleIndirect;
			
		fileBytesLeft = fileEntry->memInode->inode.i_size - fileEntry->offset;
		
		while ((bytesRead < nBytes) && (fileBytesLeft > 0))
		{
			int fileBlockOffset = fileEntry->offset / diskInfo->blockSize;
			int blockReadOffset = fileEntry->offset % diskInfo->blockSize;
			int bytesToRead = 0;
			char block[MAX_BLOCK_SIZE], *blockPnt = 0;
			
			/* Read direct block */
			if (fileBlockOffset < NUM_DIRECT_BLOCKS)
			{
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[fileBlockOffset],
							 diskInfo->blockSize, block) == -1)
					return -1;
			}
			
			/* Single indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = fileBlockOffset - NUM_DIRECT_BLOCKS;
						
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
			}
			
			/* Double indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numDoubleIndirect + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong doubleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) / (numSingleIndirect) - 1;
				int doubleBlockOffset = (fileBlockOffset - singleBlockOffset - NUM_DIRECT_BLOCKS) % (numSingleIndirect);
				
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 1],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, (char*)doubleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(doubleIndirectBlock + doubleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
			}
			
			/* Triple indirect blocks */
			else if (fileBlockOffset < (NUM_DIRECT_BLOCKS + numTripleIndirect + numDoubleIndirect + numSingleIndirect))
			{
				ulong singleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong doubleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				ulong tripleIndirectBlock[diskInfo->blockSize / sizeof(ulong)];
				int singleBlockOffset = (fileBlockOffset - NUM_DIRECT_BLOCKS) / numSingleIndirect - 1;			
				int doubleBlockOffset = (fileBlockOffset - singleBlockOffset - NUM_DIRECT_BLOCKS) / (numSingleIndirect) - 1;
				int tripleBlockOffset = (fileBlockOffset - doubleBlockOffset - singleBlockOffset - NUM_DIRECT_BLOCKS) % (numDoubleIndirect);
				
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 fileEntry->memInode->inode.i_block[NUM_DIRECT_BLOCKS + 2],
							 diskInfo->blockSize, (char*)singleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(singleIndirectBlock + singleBlockOffset)),
							 diskInfo->blockSize, (char*)doubleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(doubleIndirectBlock + doubleBlockOffset)),
							 diskInfo->blockSize, (char*)tripleIndirectBlock) == -1)
					return -1;
				if (read_blk(fileEntry->memInode->location.deviceHandle,
							 (*(ulong*)(tripleIndirectBlock + tripleBlockOffset)),
							 diskInfo->blockSize, block) == -1)
					return -1;
			}
			
			/* Calculate bytes to read from block */
			if ((nBytes - bytesRead) >= (diskInfo->blockSize - blockReadOffset))
				bytesToRead = diskInfo->blockSize - blockReadOffset;
			else
				bytesToRead = nBytes - bytesRead;
			
			/* Set block pointer and copy data */
			blockPnt = block + blockReadOffset;
			memcpy(bufPnt, blockPnt, bytesToRead);
			
			/* Increment/Decrement counters */
			bufPnt += bytesToRead;
			bytesRead += bytesToRead;
			fileBytesLeft -= bytesToRead;
			fileEntry->offset += bytesToRead;
		}
		return bytesRead;
	}
	printf("File not opened for READ mode!\n");
	return -1;
}

int do_read(char* notUsed)
{
	int bytesToRead = 0, fd = 0;
	int bytesRead = 0, i = 0;
	char buf[MAX_BLOCK_SIZE];
	
	printf("Enter FD to read: ");
	scanf("%d", &fd);
	
	printf("Enter number of bytes to read (8KB MAX): ");
	scanf("%d", &bytesToRead);
	
	bytesRead = read_file(fd, buf, bytesToRead);
	
	for (i = 0; i < bytesRead; i++)
		putchar(buf[i]);
	
	putchar('\n');
	getchar();
	return 1;
}
